﻿using System;
using System.Collections.Generic;
using System.Linq;
using ECatalog.Models.Kits;
using ECatalog.Models.Models;
using ECatalog.Models.Organizations;
using ECatalog.Models.Shops;
using ECatalog.Models.UserIU.Dto;

namespace ECatalog.Models.UserIU
{
    public class Builder : IBuilder
    {
        private readonly IShopRepository shopRepository;
        private readonly IOrganizationRepository organizationRepository;
        private readonly IKitRepository kitRepository;
        private readonly IModelRepository modelRepository;

        public Builder(IShopRepository shopRepository, IKitRepository kitRepository, IOrganizationRepository organizationRepository, IModelRepository modelRepository)
        {
            this.shopRepository = shopRepository;
            this.kitRepository = kitRepository;
            this.organizationRepository = organizationRepository;
            this.modelRepository = modelRepository;
        }

        public MainViewModel BuildViewModel()
        {
            using (var db = new DbContainer())
            {
                var serverParam = db.ServerParams.FirstOrDefault();
                if (serverParam != null)
                {
                    if (serverParam.OrganizationId != null)
                    {
                        var organization = organizationRepository.GetOrganizationById(serverParam.OrganizationId.Value);
                        if (serverParam.ShopId != null)
                        {
                            var shop = shopRepository.GetShop(serverParam.ShopId.Value);
                            if (serverParam.OrganizationId != null)
                            {
                                var kits = kitRepository.GetAllKitsInOrganization(serverParam.OrganizationId.Value);
                                var model = new MainViewModel
                                    {
                                        OrganizationLogoUrl = string.Format("/Files/Organization-{0}/Logo-{1}/320x240/{2}{3}", organization.OrganizationId, organization.LogoUrl, organization.LogoUrl, organization.TypeImage),
                                        ShopName = shop.Name,
                                        OrganizationId = organization.OrganizationId,
                                        Kits = kits.Select(k =>
                                            string.Format("/Files/Organization-{0}/Kit-{1}/{2}/800x600/{3}{4}", k.OrganizationId, k.KitId, k.ImageUrl, k.ImageUrl, k.TypeImage)
                                        ).ToArray(),
                                    };
                                return model;
                            }
                        }
                    }
                }
            }
            return new MainViewModel();
        }

        public ComplectsViewModel BuildComplectsViewModel(int organizationId, string numModel)
        {
            var md = modelRepository.GetModelByNumber(numModel);
            if (md == null)
            {
                return null;
            }

            Logger.Logger.AddToLog(true, false, true, md.ModelId);

            using (var db = new DbContainer())
            {
                var model = new ComplectsViewModel
                     {
                         OrganizationId = organizationId,
                         Offers = db.Offers.ToArray(),
                         NumModel = numModel
                     };
                return model;
            }
        }

        public ComplectsDto BuildComplectsDto(int organizationId, string numModel)
        {
            var md = modelRepository.GetModelByNumber(numModel);
            if (md == null)
            {
                return null;
            }
            var shop = shopRepository.GetActiveShop();
            if (shop == null)
            {
                return null;
            }
            var kits = kitRepository.GetAllKitsInOrganizationByModelId(organizationId, md.ModelId);
            var kitIds = kits.Select(k => k.KitId).ToArray();
            var models = modelRepository.GetModelsByKitIds(kitIds);

            var modelDtos = BuildModelDtos(organizationId, models, shop).ToArray();
            modelDtos = SortModelDtos(modelDtos, numModel).ToArray();
            var kitDtos = BuildKitDtos(organizationId, kits, modelDtos);
            var activeKit = kitDtos.Last();
            var activeModel = activeKit.ModelDtos.First();
            var result = new ComplectsDto
                {
                    //TODO: popular kitid
                    ActiveKitId = activeKit.KitId,
                    ActiveModelId = activeModel.ModelId,
                    KitDtos = kitDtos,
                    ShopMapUrl = string.Format("/Files/Organization-{0}/Shop-{1}/{2}/800x600/{3}{4}", organizationId, shop.ShopId, shop.MapUrl, shop.MapUrl, shop.TypeImage),
                    ShopId = shop.ShopId
                };
            return result;
        }

        private static List<ModelDto> SortModelDtos(ModelDto[] modelDtos, string numModel)
        {
            var list = modelDtos.Where(modelDto => modelDto.NumModel == numModel).ToList();
            list.AddRange(modelDtos.Where(modelDto => modelDto.NumModel != numModel));
            return list;
        }

        private static KitDto[] BuildKitDtos(int organizationId, IEnumerable<Kit> kits, IEnumerable<ModelDto> modelDtos)
        {
            return kits.Select(k =>
                {
                    var kitModels = modelDtos.Where(m => m.KitIds.Contains(k.KitId)).ToArray();
                    var costComplect = kitModels.Select(km => km.SalePrice).Sum();
                    if (k.Sale != null && k.Sale != 0)
                    {
                        costComplect = costComplect - ((costComplect * k.Sale.Value) / 100);
                    }
                    return new KitDto
                        {
                            CostComplect = costComplect,
                            DiscountComplect = k.Sale ?? 0,
                            LocationDtos = kitModels.Select(mds => new LocationDto
                                {
                                    ModelId = mds.LocationDto.ModelId,
                                    CatNumber = mds.LocationDto.CatNumber,
                                    CoordinateX = mds.LocationDto.CoordinateX,
                                    CoordinateY = mds.LocationDto.CoordinateY
                                }).ToArray(),
                            KitId = k.KitId,
                            ImageUrl =
                                string.Format("/Files/Organization-{0}/Kit-{1}/{2}/320x240/{3}{4}", organizationId,
                                              k.KitId, k.ImageUrl, k.ImageUrl, k.TypeImage),
                            ImageUrlFull =
                                string.Format("/Files/Organization-{0}/Kit-{1}/{2}/800x600/{3}{4}", organizationId,
                                              k.KitId, k.ImageUrl, k.ImageUrl, k.TypeImage),
                            ModelDtos = kitModels
                        };
                }).ToArray();
        }

        private IEnumerable<ModelDto> BuildModelDtos(int organizationId, IEnumerable<Model> models, Shop shop)
        {
            return models.Select(m =>
                {
                    var modelSizeIds = m.ModelSizes.Select(ms => ms.SizeId).ToArray();
                    var sizeDtos = GetSizes(modelSizeIds, shop.ShopId, m.ModelId, m.CatNumber);
                    var structuresDtos = m.Structures.Select(s => new StructuresDto { Name = s.Name, Value = s.Value }).ToArray();
                    var colorsDtos = m.Colors.Select(c => new ColorsDto { Name = c.Name, RgbNumber = c.RgbNumber }).ToArray();
                    var location = m.Locations.FirstOrDefault();
                    var locationDto = new LocationDto();
                    if (location != null)
                    {
                        var coordinates = location.Coordinates.Split(';');
                        locationDto = new LocationDto
                            {
                                ModelId = m.ModelId,
                                CatNumber = m.CatNumber,
                                CoordinateX = Convert.ToInt32(coordinates[0]),
                                CoordinateY = Convert.ToInt32(coordinates[1])
                            };
                    }
                    return new ModelDto
                        {
                            Price = m.Price,
                            Sale = m.Sale ?? 0,
                            SalePrice = m.SalePrice ?? 0,
                            KitIds = m.KitModels.Select(km => km.KitId).ToArray(),
                            ModelId = m.ModelId,
                            Description = m.Description,
                            ImageUrl =
                                string.Format("/Files/Organization-{0}/Model-{1}/{2}/320x240/{3}{4}", organizationId,
                                              m.ModelId, m.ImageUrl, m.ImageUrl, m.TypeImage),
                            ColorsDtos = colorsDtos,
                            SizeDtos = sizeDtos.ToArray(),
                            StructuresDtos = structuresDtos,
                            LocationDto = locationDto,
                            NumModel = m.CatNumber
                        };
                }).ToArray();
        }

        private IEnumerable<SizeDto> GetSizes(int[] modelSizeIds, int shopId, int modelId, string numModel)
        {
            using (var db = new DbContainer())
            {
                var sizes = db.ModelSizes.Include("Size").Where(ms => ms.ShopId == shopId).Select(ms => ms.Size).Distinct();
                foreach (var size in sizes)
                {
                    if (modelSizeIds.Contains(size.SizeId))
                    {
                        yield return new SizeDto
                            {
                                ModelId = modelId,
                                NumModel = numModel,
                                Exist = true,
                                Value = size.Value
                            };
                    }
                    else
                    {
                        yield return new SizeDto
                            {
                                ModelId = modelId,
                                NumModel = numModel,
                                Exist = false,
                                Value = size.Value
                            };
                    }
                }
            }
        }
    }
}